<!-- 事件设置 -->
<template>
    <el-dialog
        v-model="showDialog"
        :title="dialogTitle"
        width="750px"
        top="40px"
        append-to-body
        destroy-on-close
        @close="onClose"
    >
        <div class="content">
            <div class="content-header">
                <el-radio-group v-model="isCustomEvent" @change="onCustomEvent">
                    <el-radio :label="false">默认事件</el-radio>
                    <el-radio :label="true">自定义事件</el-radio>
                </el-radio-group>
                <div class="header-tools">
                    <template v-if="eventType === 'page'">
                        <template v-if="isCustomEvent">
                            <el-input v-model="config.fxTitle" placeholder="事件名称" class="tools-item" />
                            <el-input v-model="config.fxName" placeholder="事件标识" class="tools-item" />
                        </template>
                        <template v-else>
                            <el-select :modelValue="config.fxName" placeholder="请选择事件" class="tools-item">
                                <el-option
                                    v-for="item in pageEvents"
                                    :key="item.value"
                                    :label="item.label"
                                    :value="item.value"
                                    @click.native.stop="() => {
                                        config.fxTitle = item.label;
                                        config.fxName = item.value;
                                    }"
                                >
                                </el-option>
                            </el-select>
                        </template>
                    </template>
                </div>
            </div>
            <div class="content-scroll">
                <!-- <monaco-editor
                    ref="monacoRef"
                    :value="config.fxCode"
                    language="javascript"
                    width="100%"
                    height="360px"
                /> -->
                <code-editor
                    v-model="config.fxCode"
                    placeholder=""
                    :style="{ width: '100%', height: '360px' }"
                    :autofocus="true"
                    :indent-with-tab="true"
                    :tab-size="2"
                    :extensions="extensions"
                />
            </div>
        </div>
        <template #footer>
            <span class="dialog-footer">
                <el-button @click="onCancel">取消</el-button>
                <el-button type="primary" @click="onConfirm">确认</el-button>
            </span>
        </template>
    </el-dialog>
</template>

<script>
import { defineComponent, ref, computed } from 'vue'
import { useEditStore } from '@/store'
import { ElMessage } from 'element-plus'
import { randomStr, deepClone } from '@/libs/tools'
import bus from '@/libs/bus'
import useEventData from '@/libs/edit/eventData'

// import MonacoEditor from '@/components/monaco-editor'
import CodeEditor from '@/components/code-editor'
import { syntaxTree } from '@codemirror/language'
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript'

export default defineComponent({
    name: 'EventSetting',
    components: {
        // MonacoEditor
        CodeEditor
    },
    setup() {
        const editStore = useEditStore()

        const {
            pageEvents,
            widgetEvents
        } = useEventData()

        const busId = randomStr(16)
        const showDialog = ref(false)
        const config = ref({})
        // 事件类型 page页面类型，widget控件类型
        const eventType = ref('page')
        // 自定义事件
        const isCustomEvent = ref(false)

        // const monacoRef = ref(null)

        const completePropertyAfter = ['PropertyName', '.', '?.']
        const dontCompleteIn = ['TemplateString', 'LineComment', 'BlockComment', 'VariableDefinition', 'PropertyDefinition']
        
        const prototypeObject = computed(() => {
            const appStateKeys = {}
            const pageStateKeys = {}
            const pageParamsKeys = {}
            Object.keys(appState.value).forEach(key => appStateKeys[key] = '')
            Object.keys(pageState.value).forEach(key => pageStateKeys[key] = '')
            Object.keys(pageParams.value).forEach(key => pageParamsKeys[key] = '')

            return {
                $app: {
                    dataset: {
                        state: {
                            ...appStateKeys
                        }
                    }
                },
                $page: {
                    dataset: {
                        state: {
                            ...pageStateKeys
                        },
                        params: {
                            ...pageParamsKeys
                        }
                    }
                }
            }
        })

        function completeFromGlobalScope(context) {
            const nodeBefore = syntaxTree(context.state).resolveInner(context.pos, -1)

            if (completePropertyAfter.includes(nodeBefore.name) && nodeBefore.parent?.name == 'MemberExpression') {
                const object = nodeBefore.parent.getChild('Expression')
                // console.log(object, nodeBefore)
                if (object?.name == 'VariableName') {
                    const from = /\./.test(nodeBefore.name) ? nodeBefore.to : nodeBefore.from
                    const variableName = context.state.sliceDoc(object.from, object.to)
                    // console.log(from, variableName, prototypeObject.value)
                    if (typeof prototypeObject.value[variableName] == 'object') {
                        return completeProperties(from, prototypeObject.value[variableName])
                    }
                }
                // todo 有bug
                // else if (completePropertyAfter.includes(nodeBefore.name) && object?.name == 'MemberExpression') {
                //     const from = /\./.test(nodeBefore.name) ? nodeBefore.to : nodeBefore.from
                //     const variableName = context.state.sliceDoc(object.from, object.to)
                //     console.log(object, from, variableName)
                //     if (typeof eval(`prototypeObject.value.${variableName}`) == 'object') {
                //         return completeProperties(from, eval(`prototypeObject.value.${variableName}`))
                //     }
                // }
            } else if (nodeBefore.name == 'VariableName') {
                return completeProperties(nodeBefore.from, prototypeObject.value)
            } else if (context.explicit && !dontCompleteIn.includes(nodeBefore.name)) {
                return completeProperties(context.pos, prototypeObject.value)
            }
            return null
        }

        function completeProperties(from, object) {
            let options = []
            for (let name in object) {
                options.push({
                    label: name,
                    type: typeof object[name] == 'function' ? 'function' : 'variable',
                    detail: '描述'
                })
            }
            return {
                from,
                options,
                validFor: /^[\w$]*$/
            }
        }

        const globalJavaScriptCompletions = javascriptLanguage.data.of({
            autocomplete: completeFromGlobalScope
        })

        const extensions = [
            javascript(),
            globalJavaScriptCompletions
        ]

        const dialogTitle = computed(() => {
            if (eventType.value === 'page') {
                return '页面事件设置'
            }
        })

        const appData = computed(() => editStore.appData)
        const pageData = computed(() => editStore.pageData)
        // 全局的普通变量/模型变量
        const appState = computed(() => appData.value?.data?.dataset?.state || {})
        // 当前页面的普通变量/模型变量
        const pageState = computed(() => pageData.value?.dataset?.state || {})
        // 当前页面的参数变量
        const pageParams = computed(() => pageData.value?.dataset?.params || {})

        const widgetListFlat = computed(() => editStore.widgetListFlat)
        const widgetList = computed(() => {
            return Object.values(widgetListFlat.value).filter(item => {
                return Object.keys(widgetEvents).includes(item.widgetData.eles.type)
            }).map(item => ({
                label: item.widgetData.eles.name || item.widgetData.component.title,
                value: item.widgetData.eles.id
            }))
        })
        const widgetEventList = computed(() => {
            const widgetType = widgetListFlat.value?.[config.value?.id]?.widgetData?.eles?.type
            return widgetEvents?.[widgetType] || []
        })

        /**
         * 打开弹窗
         * @param {String} type 事件类型 page页面类型，widget控件类型
         * @param {Object} data 事件数据
         */
        const show = ({ type = 'page', data = {} }) => {
            eventType.value = type
            if (type === 'page') {
                config.value = deepClone({
                    fxTitle: '',
                    fxName: '',
                    fxCode: '',
                    ...data
                })
                isCustomEvent.value = !!config.value.fxName && !pageEvents.some(item => item.value === config.value.fxName)
            }
            showDialog.value = true
            return new Promise((resolve, reject) => {
                bus.on(`${busId}-confirm`, () => {
                    showDialog.value = false
                    // config.value.fxCode = monacoRef.value.getValue()
                    resolve(config.value)
                })
                bus.on(`${busId}-cancel`, () => {
                    showDialog.value = false
                    reject()
                })
            })
        }

        const onClose = () => {
            bus.off(`${busId}-confirm`)
            bus.off(`${busId}-cancel`)
        }

        const onCustomEvent = status => {
            if (eventType.value === 'page') {
                Object.assign(config.value, {
                    fxTitle: '',
                    fxName: ''
                })
            }
        }

        const onCancel = () => {
            bus.emit(`${busId}-cancel`)
        }
        const onConfirm = () => {
            if (eventType.value === 'page') {
                if (isCustomEvent.value) {
                    if (!config.value.fxTitle || !config.value.fxName) {
                        ElMessage({
                            message: '事件标题或事件名称不能为空',
                            type: 'warning'
                        })
                        return
                    }
                } else {
                    if (!config.value.fxName) {
                        ElMessage({
                            message: '请选择事件',
                            type: 'warning'
                        })
                        return
                    }
                }
            }

            bus.emit(`${busId}-confirm`)
        }

        return {
            showDialog,
            dialogTitle,
            config,
            eventType,
            isCustomEvent,
            // monacoRef,

            extensions,

            widgetList,
            widgetEventList,

            pageEvents,
            widgetEvents,

            show,
            onClose,
            onCustomEvent,
            onCancel,
            onConfirm
        }
    }
})
</script>

<style lang="less" scoped>
.content {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    .content-header {
        .header-tools {
            display: flex;
            align-items: center;
            margin-top: 10px;
            .tools-item {
                width: 180px;
                & + .tools-item {
                    margin-left: 10px;
                }
            }
            .tools-item-icon {
                margin: 0 10px 0 5px;
            }
        }
    }
    .content-scroll {
        border: 1px solid var(--edit-border-color);
        margin-top: 10px;
    }
}
</style>